#region Using directives

using System;
using System.Diagnostics;
using System.Collections.Generic;

#endregion

using Weazel.Gezel.Model;
using Weazel.Gezel.Model.Errors;
using Weazel.Math;

namespace Weazel.Gezel.Parser
{
  /// <summary>
  /// Datapath : 
  ///     DP DatapathId DatapathIo LEFT_BRACE DatapathDefinition RIGHT_BRACE
  ///   | DP DatapathId COLON DatapathIdCopy; 
  /// 
  /// Datapath : 
  ///     DP Identifer DatapathIo LEFT_BRACE DatapathDefinition RIGHT_BRACE
  ///   | DP Identifer COLON Identifier; /// 
  /// </summary>
  public static class ParseDatapath
  {
    public static readonly Set<Token> First = new Set<Token>(
      Token.Dp
    );

    public static void Parse(Set<Token> follow, Tokenizer t, Weazel.Gezel.Model.Model parent)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseDatapath'",
        ConsoleColor.Red
      );

      Set<Token> current = new Set<Token>(
        Token.Identifier,
        Token.LeftBrace,
        Token.RightBrace,
        Token.Colon
      );

      current = current.Union(ParseDatapathIo.First);
      current = current.Union(ParseDatapathDefinition.First);

      t.Accept(Token.Dp, follow.Union(current));
		
			Position position = t.CurrentStartPosition;

      string datapathName = null;
      if (t.CurrentToken == Token.Identifier)
      {
        datapathName = t.CurrentString;        
      }
     
      t.Accept(Token.Identifier, follow.Union(current));

      Datapath dp = new Datapath(parent, datapathName, position, null);

      t.Check(follow.Union(current));

      current.Remove(Token.Colon);
     //   current.Remove(ParseDatapathIo.First);

      if (ParseDatapathIo.First.Contains(t.CurrentToken))
      {
        //current.Remove(Token.Identifier);
        ParseDatapathIo.Parse(follow.Union(current), t, dp);

        current.Remove(Token.LeftBrace);
        t.Accept(Token.LeftBrace, follow.Union(current));

        ParseDatapathDefinition.Parse(follow.Union(current), t, dp);

        current.Remove(Token.RightBrace);
        t.Accept(Token.RightBrace, follow);
      }
      else if (t.CurrentToken == Token.Colon)
      {
        t.Accept(Token.Colon, follow.Union(Token.Identifier));

        if (t.CurrentToken == Token.Identifier && datapathName != null)
        {
          dp.ClonedFromDatapath = t.CurrentString;
        }

        t.Accept(Token.Identifier, follow);
      }
      else if(t.CurrentToken == Token.LeftBrace)
      {
        // datapath contains no ports .. print a warning or something 

        // continue parsing as if a port list was actually found ..

        current.Remove(Token.Identifier);        
        current.Remove(Token.LeftBrace);
        t.Accept(Token.LeftBrace, follow.Union(current));

        ParseDatapathDefinition.Parse(follow.Union(current), t, dp);

        current.Remove(Token.RightBrace);

				dp.EndPosition = t.CurrentEndPosition;

        t.Accept(Token.RightBrace, follow);
      }
      else
      {
        t.Errors.Add(
          new UnexpectedTokenParseError(
            t.CurrentPosition,
            t.CurrentToken,
            follow.Union(current)
          )
        );
      }

      if (datapathName != null)
      {
        // check that the dp name is unique
        if (parent.Datapaths.ContainsKey(datapathName))
        {
          t.Errors.Add(
            new DuplicateDatapathNameParseError(
              dp,
              parent.Datapaths[datapathName]
            )
          );
        }
        else
        {
          parent.Datapaths.Add(datapathName, dp);
        }
      }

      ParserDebug.WriteLine(
        "Leaving 'ParseDatapath'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// DatapathIo : 
  ///     Nothing
  ///   | LEFT_PARENTHSIS PortIoList RIGHT_PARENTHESIS
  /// 
  /// </summary>
  public static class ParseDatapathIo
  {
    public static readonly Set<Token> First = new Set<Token>(
      Token.LeftParenthesis
      // "nothing" should be included here ..
    );

    public static void Parse(Set<Token> follow, Tokenizer t, Datapath dp)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseDatapathIo'",
        ConsoleColor.Red
      );

      Set<Token> current = new Set<Token>(
        Token.LeftParenthesis,
        Token.RightParenthesis
      );

      current = current.Union(ParsePortIoList.First);

      t.Check(follow.Union(current));
      
      if (t.CurrentToken == Token.LeftParenthesis)
      {
        current.Remove(Token.LeftParenthesis);
        t.Accept(Token.LeftParenthesis, follow.Union(current));

        current.Remove(ParsePortIoList.First);
        List<PortInfo> ports = ParsePortIoList.Parse(follow.Union(current), t);

        int pos = 0;
        foreach(PortInfo port in ports)
        {
          Port p = port.InPort ? 
            (Port) new InPort(
              dp,
              port.Name,
              port.Type.Width,
              port.Type.Signed,
              port.PortPosition,
              port.StartPosition,
							port.EndPosition
            )
         :
            (Port) new OutPort(
              dp,
              port.Name,
              port.Type.Width,
              port.Type.Signed,
              port.PortPosition,
							port.StartPosition,
							port.EndPosition
            );

          // first check if a port with this name already exists..
          if (dp.OutPorts.ContainsKey(port.Name))         
            t.Errors.Add(new DuplicateSymbolDefinitionParseError(p, dp.OutPorts[port.Name], dp));          
          else if(dp.InPorts.ContainsKey(port.Name))          
            t.Errors.Add(new DuplicateSymbolDefinitionParseError(p, dp.InPorts[port.Name], dp));          
          else if(dp.Signals.ContainsKey(port.Name))          
            t.Errors.Add(new DuplicateSymbolDefinitionParseError(p, dp.Signals[port.Name], dp));
          else if(dp.Registers.ContainsKey(port.Name))
            t.Errors.Add(new DuplicateSymbolDefinitionParseError(p, dp.Registers[port.Name], dp));
          else
          {
            if (port.InPort)
              dp.InPorts.Add(
                port.Name,
                (InPort) p
              );
            else
              dp.OutPorts.Add(
                port.Name,
                (OutPort) p
              );

            pos++;
          }
        }

        t.Accept(Token.RightParenthesis, follow);
      }
      else
      {
        // nothing, perfectly legal..
      }

      ParserDebug.WriteLine(
        "Leaving 'ParseDatapathIo'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// dp_def:  dp_el
  ///    |  dp_def dp_el
  /// ;
  /// </summary>
  public static class ParseDatapathDefinition
  {
    public static readonly Set<Token> First = ParseDatapathElement.First;

    public static void Parse(Set<Token> follow, Tokenizer t, Datapath dp)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseDatapathDefinition'",
        ConsoleColor.Red
      );

      bool done = false;

      do
      {
        t.Check(follow.Union(First));

        if (ParseDatapathElement.First.Contains(t.CurrentToken))
          ParseDatapathElement.Parse(follow.Union(First), t, dp);
        else
          done = true;

      } while (!done);

      ParserDebug.WriteLine(
        "Leaving 'ParseDatapathDefinition'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// dp_el:   com_sig_el
  ///    |  sfg_el 
  ///    |  dp_inc_el
  ///    |  trace_sig_el 
  ///    ;
  /// </summary>
  public static class ParseDatapathElement
  {
    public static readonly Set<Token> First =
      new Set<Token>().Union(ParseSignalElement.First).Union(ParseSfgElement.First).
      Union(ParseDatapathIncludeElement.First).Union(ParseTraceSignalElement.First);

    public static void Parse(Set<Token> follow, Tokenizer t, Datapath dp)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseDatapathElement'",
        ConsoleColor.Red
      );

      // branch only
      t.Check(First);

      if (ParseSignalElement.First.Contains(t.CurrentToken))
      {
        ParseSignalElement.Parse(follow, t, dp);
      }
      else if (ParseSfgElement.First.Contains(t.CurrentToken))
      {
        ParseSfgElement.Parse(follow, t, dp);
      }
      else if (ParseDatapathIncludeElement.First.Contains(t.CurrentToken))
      {
        ParseDatapathIncludeElement.Parse(follow, t, dp);
      }
      else if (ParseTraceSignalElement.First.Contains(t.CurrentToken))
      {
        ParseTraceSignalElement.Parse(follow, t, dp);
      }
      else
      {
        t.Errors.Add(
          new UnexpectedTokenParseError(
            t.CurrentPosition,
            t.CurrentToken,
            First
          )
        );
      }

      ParserDebug.WriteLine(
        "Leaving 'ParseDatapathElement'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// SignalElement : 
  ///     StorageType SignalId COLON SignalType SEMICOLON
  ///   | LOOKUP LookupTableIdList COLON SignalType ASSIGN LookupTableContent SEMICOLON;
  /// 
  /// SignalElement : 
  ///     SIG SignalIdList COLON SignalType SEMICOLON
  ///   | REG SignalIdList COLON SignalType SEMICOLON
  ///   | LOOKUP LookupTableIdList COLON SignalType ASSIGN LookupTableContent SEMICOLON;
  /// </summary>
  public static class ParseSignalElement
  {
    public static readonly Set<Token> First = new Set<Token>(
      Token.Sig,
      Token.Reg,
      Token.Lookup
    );

    public static void Parse(Set<Token> follow, Tokenizer t, Datapath dp)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseSignalElement'",
        ConsoleColor.Red
      );

      Set<Token> current = new Set<Token>(
        Token.Sig,
        Token.Reg,
        Token.Lookup,
        Token.Colon,
        Token.Assign,
        Token.Semicolon
      );

      current = current.Union(ParseList.First);
      current = current.Union(ParseLookupTableContent.First);

      t.Check(follow.Union(current));

      current.Remove(Token.Lookup, Token.Sig, Token.Reg);

      // note: we do not remove either ParseSignalIdList.First 
      // or ParseLookupTableIdList.First since they both contain
      // Identifier which is valid anyhow ,...

      Position position = t.CurrentPosition;

      if (t.CurrentToken == Token.Lookup)
      {        
        t.Accept(Token.Lookup, follow.Union(current));

        current.Remove(ParseList.First);
        List<CompoundPosition> positions = new List<CompoundPosition>();
        List<string> names = ParseList.Parse(follow.Union(current), t, ref positions);

        current.Remove(Token.Colon);
        t.Accept(Token.Colon, follow.Union(current));

        current.Remove(ParseSignalType.First);
        SignalTypeInfo type = ParseSignalType.Parse(follow.Union(current), t);

        current.Remove(Token.Assign);
        t.Accept(Token.Assign, follow.Union(current));

        current.Remove(ParseLookupTableContent.First);
        Integer[] values = ParseLookupTableContent.Parse(follow.Union(current), t, type);

        t.Accept(Token.Semicolon, follow);

				if (names.Count > 0)
				{
					LookupTable table =
						new LookupTable(
							dp,
							names[0],
							values,
							type.Width,
							type.Signed,
							positions[0].StartPosition,
							positions[0].EndPosition
						);

					if (dp.GetIdentifier(names[0]) != null)
					{
						ErrorMessage message = new ErrorMessage();
						message.AddString("Duplicate definition of identifier '");
						message.AddEntity(table);
						message.AddString("' at ");
						message.AddPosition(table.StartPosition);
						message.AddString(". Previously defined at ");
						message.AddPosition(dp.GetIdentifier(names[0]).StartPosition);
						message.AddString(".");

						t.Errors.Add(new ParseError(ParseErrorType.DuplicateSymbolDefintion, message));
					}

					dp.LookupTables.Add(names[0], table);
				}
      }
      else if (t.CurrentToken == Token.Sig)
      {
        current.Remove(ParseLookupTableContent.First);

        t.Accept(Token.Sig, follow.Union(current));

        current.Remove(ParseList.First);
        List<CompoundPosition> positions = new List<CompoundPosition>();
        List<string> names = ParseList.Parse(follow.Union(current), t, ref positions);

        current.Remove(Token.Colon);
        t.Accept(Token.Colon, follow.Union(current));

        SignalTypeInfo type = ParseSignalType.Parse(follow.Union(current), t);

        t.Accept(Token.Semicolon, follow);

				for (int i = 0; i < names.Count; i++)
				{
					Signal sig = 
						new Signal(
							dp, 
							names[i], 
							type.Width, 
							type.Signed, 
							positions[i].StartPosition, 
							positions[i].EndPosition
						);

					// check that a signal with this name has not already been added ..
					if(dp.GetIdentifier(names[i]) != null)
					{						
						ErrorMessage message = new ErrorMessage();
						message.AddString("Duplicate definition of identifier '");
						message.AddEntity(sig);
						message.AddString("' at ");
						message.AddPosition(sig.StartPosition);
						message.AddString(". Previously defined at ");
						message.AddPosition(dp.GetIdentifier(names[i]).StartPosition);
						message.AddString(".");

						t.Errors.Add(new ParseError(ParseErrorType.DuplicateSymbolDefintion, message));							
					}
					else
					{
						// all is well, add signal to datapath
						dp.Signals.Add(names[i], sig);
					}
				}
      }
      else if (t.CurrentToken == Token.Reg)
      {
        current.Remove(ParseLookupTableContent.First);

        t.Accept(Token.Reg, follow.Union(current));

        current.Remove(ParseList.First);
        List<CompoundPosition> positions = new List<CompoundPosition>();
        List<string> names = ParseList.Parse(follow.Union(current), t, ref positions);

        current.Remove(Token.Colon);
        t.Accept(Token.Colon, follow.Union(current));

        SignalTypeInfo type = ParseSignalType.Parse(follow.Union(current), t);

        t.Accept(Token.Semicolon, follow);

				for (int i = 0; i < names.Count; i++)
				{
					Register reg = 
						new Register(
							dp, 
							names[i], 
							type.Width, 
							type.Signed, 
							positions[i].StartPosition, 
							positions[i].EndPosition
						);

					// check that a signal with this name has not already been added ..
					if (dp.GetIdentifier(names[i]) != null)
					{
						ErrorMessage message = new ErrorMessage();
						message.AddString("Duplicate definition of identifier '");
						message.AddEntity(reg);
						message.AddString("' at ");
						message.AddPosition(reg.StartPosition);
						message.AddString(". Previously defined at ");
						message.AddPosition(dp.GetIdentifier(names[i]).StartPosition);
						message.AddString(".");

						t.Errors.Add(new ParseError(ParseErrorType.DuplicateSymbolDefintion, message));
					}
					else
					{
						dp.Registers.Add(names[i], reg);
					}
				}
      }
      else
      {
        t.Errors.Add(
          new UnexpectedTokenParseError(
            t.CurrentPosition,
            t.CurrentToken,
            follow.Union(current)
          )
        );
      }

      ParserDebug.WriteLine(
        "Leaving 'ParseSignalElement'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// dp_inc_el:  USE dp_inc_id RBRACKET_OPEN dp_inc_pin_list RBRACKET_CLOSE SEMICOLON {}
  /// </summary>
  public static class ParseDatapathIncludeElement 
  {
    public static readonly Set<Token> First = new Set<Token>(
      Token.Use
    );

    public static void Parse(Set<Token> follow, Tokenizer t, Datapath dp)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseDatapathIncludeElement'",
        ConsoleColor.Red
      );

      Set<Token> current = new Set<Token>(
        // Token.Use,
        Token.Identifier,
        Token.LeftParenthesis,
        Token.RightParenthesis,
        Token.Semicolon
      );

      current = current.Union(ParseList.First);

      t.Accept(Token.Use, follow.Union(current));

      string name = t.CurrentToken == Token.Identifier ? t.CurrentString : null;

      // do not remove 'Identifer' from set (also in list)
      t.Accept(Token.Identifier, follow.Union(current));

      current.Remove(Token.LeftParenthesis);
      t.Accept(Token.LeftParenthesis, follow.Union(current));

      current.Remove(ParseList.First);
      List<CompoundPosition> positions = new List<CompoundPosition>();
      List<string> list = ParseList.Parse(follow.Union(current), t, ref positions);

      current.Remove(Token.RightParenthesis);
      t.Accept(Token.RightParenthesis, follow.Union(current));
      
      t.Accept(Token.Semicolon, follow);

      if (name != null)
      {
          if (dp.ChildDatapathRefs.ContainsKey(name))
          {
              ErrorMessage message = new ErrorMessage();
              message.AddString(string.Format("The datapath '{0}' has already been used in combination with a 'use' at ", name));
              message.AddPosition(t.CurrentPosition);
              message.AddString(" (use datapath cloning)");

              ParseError error = new ParseError(ParseErrorType.DuplicateDatapathDefintion, message);

              t.Errors.Add(error);
          }
          else
          {
              dp.ChildDatapathRefs.Add(name, list.ToArray());
          }
      }

      ParserDebug.WriteLine(
        "Leaving 'ParseDatapathIncludeElement'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// sfg_el: SFG ID  BRACE_OPEN sfg_internals BRACE_CLOSE;
  /// </summary>
  public static class ParseSfgElement
  {
    public static readonly Set<Token> First = new Set<Token>(
      Token.Sfg
    );

    public static void Parse(Set<Token> follow, Tokenizer t, Datapath dp)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseSfgElement'",
        ConsoleColor.Red
      );

      Set<Token> current = new Set<Token>(
        // Token.Sfg,
        Token.Identifier,
        Token.LeftBrace,
        Token.RightBrace
      );

      current = current.Union(ParseSfgInternals.First);
			
      Position startPosition = t.CurrentPosition;

      t.Accept(Token.Sfg, follow.Union(current));

      string name = t.CurrentToken == Token.Identifier ? 
          t.CurrentString 
        : null;

      current.Remove(Token.Identifier);
      t.Accept(Token.Identifier, follow.Union(current));

      current.Remove(Token.LeftBrace);
      t.Accept(Token.LeftBrace, follow.Union(current));

      SignalFlowGraph sfg = 
				new SignalFlowGraph(
					dp, 
					name, 
					startPosition,
					null
				);

      current.Remove(ParseSfgInternals.First);
      ParseSfgInternals.Parse(follow.Union(current), t, sfg);

			sfg.EndPosition = t.CurrentEndPosition;

      current.Remove(Token.RightBrace);
      t.Accept(Token.RightBrace, follow.Union(current));

      if (name != null)
      {
        // check if the dp already has an sfg with the same name
        if (dp.SignalFlowGraphs.ContainsKey(name))
        {
          t.Errors.Add(
            new DuplicateSignalFlowGraphNameParseError(
              sfg,
              dp.SignalFlowGraphs[name],
              dp
            )
          );
        }
        else
        {
          dp.SignalFlowGraphs.Add(name, sfg);
        }
      }

      ParserDebug.WriteLine(
        "Leaving 'ParseSfgElement'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// sfg_internals: local_sig_el SEMICOLON expression_list
  ///           | expression_list
  ///           | 
  ///           ;
  /// </summary>
  public static class ParseSfgInternals
  {
    public static readonly Set<Token> First = new Set<Token>()
      .Union(ParseExpressionList.First)
      .Union(ParseLocalSignalElement.First);

    public static void Parse(Set<Token> follow, Tokenizer t, SignalFlowGraph sfg)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseSfgInternals'",
        ConsoleColor.Red
      );

      Set<Token> current = new Set<Token>(
        Token.Semicolon
      );

      current = current.Union(ParseExpressionList.First);
      current = current.Union(ParseLocalSignalElement.First);

      t.Check(follow.Union(current));
        
      if(ParseLocalSignalElement.First.Contains(t.CurrentToken))
      {
        current.Remove(ParseLocalSignalElement.First);
        ParseLocalSignalElement.Parse(follow.Union(current), t, sfg);

        current.Remove(Token.Semicolon);
        t.Accept(Token.Semicolon, follow.Union(current));

        Expression e = ParseExpressionList.Parse(follow.Union(current), t);

        if (e is ListExpression)
          sfg.Expressions.AddRange(((ListExpression)e).List);
        else
          sfg.Expressions.Add(e);       
      }
      else if(ParseExpressionList.First.Contains(t.CurrentToken))
      {
        Expression e = ParseExpressionList.Parse(follow.Union(current), t);

        if (e is ListExpression)
          sfg.Expressions.AddRange(((ListExpression)e).List);
        else
          sfg.Expressions.Add(e);
      }
      else
      {
        // perfectly legal ..
      }

      ParserDebug.WriteLine(
        "Leaving 'ParseSfgInternals'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// local_sig_el: storage_type local_sig_id_list COLON sig_type 
  ///;
  /// </summary>
  public static class ParseLocalSignalElement
  {
    public static readonly Set<Token> First = new Set<Token>
      (Token.Sig, Token.Reg);

    public static void Parse(Set<Token> follow, Tokenizer t, SignalFlowGraph sfg)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseLocalSignalElement'",
        ConsoleColor.Red
      );

      Set<Token> current = new Set<Token>(
        Token.Sig,
        Token.Reg,
        Token.Colon
      );

      current = current.Union(ParseList.First);
      current = current.Union(ParseSignalType.First);

      t.Check(current.Union(follow));

      current.Remove(Token.Sig, Token.Reg);

      Token storageType = Token.Nil;
      Position position = null;

      if (t.CurrentToken == Token.Sig)
      {
        position = t.CurrentPosition;
        t.Accept(Token.Sig, follow.Union(current));
        storageType = Token.Sig;
      }
      else if (t.CurrentToken == Token.Reg)
      {
        position = t.CurrentPosition;
        t.Accept(Token.Reg, follow.Union(current));
        storageType = Token.Reg;
      }
      else
      {
        t.Errors.Add(
          new UnexpectedTokenParseError(
            t.CurrentPosition,
            t.CurrentToken,
            follow.Union(current)
          )
        );
      }

      current.Remove(ParseList.First);
      List<CompoundPosition> positions = new List<CompoundPosition>();
      List<string> names = ParseList.Parse(follow.Union(current), t, ref positions);

      current.Remove(Token.Colon);
      t.Accept(Token.Colon, follow.Union(current));

      SignalTypeInfo type = ParseSignalType.Parse(follow, t);

      if (storageType == Token.Reg)
      {
        if(names.Count > 0)
          sfg.Register = 
						new Register(
							(Datapath)sfg.Parent, 
							names[0], 
							type.Width, 
							type.Signed,
							positions[0].StartPosition,
							positions[0].EndPosition
						);
      }
      else if (storageType == Token.Sig)
      {
        if(names.Count > 0)
          sfg.Signal = 
						new Signal(
							(Datapath)sfg.Parent, 
							names[0], 
							type.Width, 
							type.Signed, 
							positions[0].StartPosition,
							positions[0].EndPosition
						);
      }
      else
      {
        // error .. (already caught)
      }

      ParserDebug.WriteLine(
        "Leaving 'ParseLocalSignalElement'",
        ConsoleColor.Yellow
      );
    }
  }

  /// <summary>
  /// trace_sig_el:
	///   TRACE RBRACKET_OPEN trace_sig_def COMMA trace_file_def RBRACKET_CLOSE SEMICOLON;
  /// </summary>
  public static class ParseTraceSignalElement
  {
    public static readonly Set<Token> First = new Set<Token>(
      Token.TraceDirective
    );

    public static void Parse(Set<Token> follow, Tokenizer t, Datapath dp)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseTraceSignalElement'",
        ConsoleColor.Red
      );

      Set<Token> current = new Set<Token>(
        // Token.TraceDirective,
        Token.LeftParenthesis,
        Token.Comma,
        Token.Str,
        Token.RightParenthesis,
        Token.Semicolon
      );

      current = current.Union(ParseIorExpression.First);
	
			Position startPosition = t.CurrentPosition;

      t.Accept(Token.TraceDirective, follow.Union(current));

      current.Remove(Token.LeftParenthesis);
      t.Accept(Token.LeftParenthesis, follow.Union(current));

      current.Remove(ParseIorExpression.First);
      Expression e = ParseIorExpression.Parse(follow.Union(current), t);

      current.Remove(Token.Comma);
      t.Accept(Token.Comma, follow.Union(current));

      string file = t.CurrentToken == Token.Str ? t.CurrentString : null;

      current.Remove(Token.Str);
      t.Accept(Token.Str, follow.Union(current));

      current.Remove(Token.RightParenthesis);
      t.Accept(Token.RightParenthesis, follow.Union(current));

			Position endPosition = t.CurrentEndPosition;

      t.Accept(Token.Semicolon, follow);

      if(file != null)
        dp.Tracers.Add(new SignalTrace(dp, e, file, startPosition, endPosition));

      ParserDebug.WriteLine(
        "Leaving 'ParseTraceSignalElement'",
        ConsoleColor.Yellow
      );
    }
  }

  public static class ParseNegativeNumber
  {
    public static readonly Set<Token> First = new Set<Token>(
      Token.Sub
    );

    public static Integer Parse(Set<Token> follow, Tokenizer t, SignalTypeInfo type)
    {
      Integer result = new Integer(type.Width, type.Signed);

      Set<Token> current = new Set<Token>(
        Token.Number
      );

      t.Accept(Token.Sub, follow.Union(current));

      if (t.CurrentToken == Token.Number)
      {
        result.Assign( "-" + t.CurrentString);
      }

      t.Accept(Token.Number, follow.Union(current));

      return result;
    }
  }

  /// <summary>
  /// LookupTableContent : 
  ///   LEFT_BRACE LookupTableElementList RIGHT_BRACE
  /// 
  /// LookupTableElementList :
  ///     Identifier 
  ///   | Identifier COMMA LookupTableElementList
  /// 
  /// </summary>
  public static class ParseLookupTableContent
  {
    public static readonly Set<Token> First = new Set<Token>(
      Token.LeftBrace
    );

    public static Integer[] Parse(Set<Token> follow, Tokenizer t, SignalTypeInfo type)
    {
      ParserDebug.WriteLine(
        "Entering 'ParseLookupTableContent'",
        ConsoleColor.Red
      );

      List<Integer> result = new List<Integer>();

      Set<Token> current = new Set<Token>(
        // Token.LeftBrace,
        Token.Identifier,
        Token.Comma,
        Token.Number,
        Token.RightBrace
      );

      current = current.Union(ParseNegativeNumber.First);

      t.Accept(Token.LeftBrace, follow.Union(current));

      bool done = false;

      do
      {
        if (t.CurrentToken == Token.Sub)
        {
          result.Add(ParseNegativeNumber.Parse(follow, t, type));
        }
        else if (t.CurrentToken == Token.Number)
        {
          if (t.CurrentToken == Token.Number)
            result.Add(new Integer(t.CurrentString));

          t.Accept(Token.Number, follow.Union(current));

          t.Check(follow.Union(current));
        }
        else 
        {
          t.Errors.Add(
            new UnexpectedTokenParseError(
              t.CurrentPosition,
              t.CurrentToken,
              follow.Union(current)
            )
          );
        }

        if (t.CurrentToken == Token.Comma)
          t.Accept(Token.Comma, follow.Union(current));
        else
          done = true;
      }
      while (!done);

      t.Accept(Token.RightBrace, follow);

      ParserDebug.WriteLine(
        "Leaving 'ParseLookupTableContent'",
        ConsoleColor.Yellow
      );

      return result.ToArray();
    }
  }
}